package com.cencat.user.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cencat.common.utils.PaginationHelper;
import com.cencat.common.response.PageResponse;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.util.StringUtils;
import org.springframework.beans.BeanUtils;
import com.cencat.common.enums.ErrorCode;
import com.cencat.common.exception.BusinessException;
import com.cencat.user.config.CacheConfig;
import com.cencat.user.dto.UserRoleDTO;
import com.cencat.user.dto.UserRoleQueryDTO;
import com.cencat.user.entity.UserRole;
import com.cencat.user.mapper.UserRoleMapper;
import com.cencat.user.service.UserRoleService;
import com.cencat.user.vo.UserRoleVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 用户角色关联服务实现类
 * @author cencat
 * @since 2024-01-01
 */
@Service
@Slf4j
public class UserRoleServiceImpl implements UserRoleService {

    @Autowired
    private UserRoleMapper userRoleMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = "userRolePage", allEntries = true)
    public Boolean assignUserRoles(UserRoleDTO dto) throws BusinessException {
        try {
            // 参数校验
            if (dto == null || dto.getUserId() == null || CollectionUtils.isEmpty(dto.getRoleIds()) || dto.getTenantId() == null) {
                throw new BusinessException(ErrorCode.PARAM_ERROR);
            }

            // 检查是否已存在关联关系，过滤掉已存在的
            List<Long> newRoleIds = new ArrayList<>();
            for (Long roleId : dto.getRoleIds()) {
                UserRole existingUserRole = userRoleMapper.selectByUserIdAndRoleId(dto.getUserId(), roleId, dto.getTenantId());
                if (existingUserRole == null) {
                    newRoleIds.add(roleId);
                }
            }

            if (CollectionUtils.isEmpty(newRoleIds)) {
                log.info("用户角色关联已存在，无需重复分配: userId={}, roleIds={}", dto.getUserId(), dto.getRoleIds());
                return true;
            }

            // 批量插入用户角色关联
            List<UserRole> userRoles = new ArrayList<>();
            LocalDateTime now = LocalDateTime.now();
            for (Long roleId : newRoleIds) {
                UserRole userRole = new UserRole();
                userRole.setUserId(dto.getUserId());
                userRole.setRoleId(roleId);
                userRole.setTenantId(dto.getTenantId());
                userRole.setCreateTime(now);
                userRole.setCreateBy(1L); // 这里应该从上下文获取当前用户
                userRoles.add(userRole);
            }

            int result = userRoleMapper.batchInsert(userRoles);
            if (result <= 0) {
                throw new BusinessException(ErrorCode.OPERATION_ERROR);
            }

            log.info("分配用户角色成功: userId={}, roleIds={}, count={}", dto.getUserId(), newRoleIds, result);
            return true;
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("分配用户角色失败: userId={}, roleIds={}, error={}", dto.getUserId(), dto.getRoleIds(), e.getMessage(), e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "分配用户角色失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = "userRolePage", allEntries = true)
    public Boolean removeUserRoles(UserRoleDTO dto) throws BusinessException {
        try {
            // 参数校验
            if (dto == null || dto.getUserId() == null || CollectionUtils.isEmpty(dto.getRoleIds()) || dto.getTenantId() == null) {
                throw new BusinessException(ErrorCode.PARAM_ERROR);
            }

            // 批量删除用户角色关联
            int result = userRoleMapper.deleteByUserIdAndRoleIds(dto.getUserId(), dto.getRoleIds(), dto.getTenantId());
            
            log.info("移除用户角色成功: userId={}, roleIds={}, count={}", dto.getUserId(), dto.getRoleIds(), result);
            return true;
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("移除用户角色失败: userId={}, roleIds={}, error={}", dto.getUserId(), dto.getRoleIds(), e.getMessage(), e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "移除用户角色失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = "userRolePage", allEntries = true)
    public Boolean updateUserRoles(UserRoleDTO dto) throws BusinessException {
        try {
            // 参数校验
            if (dto == null || dto.getUserId() == null || dto.getTenantId() == null) {
                throw new BusinessException(ErrorCode.PARAM_ERROR);
            }

            // 先删除用户的所有角色关联
            userRoleMapper.deleteByUserId(dto.getUserId(), dto.getTenantId());

            // 如果有新角色，则添加
            if (!CollectionUtils.isEmpty(dto.getRoleIds())) {
                List<UserRole> userRoles = new ArrayList<>();
                LocalDateTime now = LocalDateTime.now();
                for (Long roleId : dto.getRoleIds()) {
                    UserRole userRole = new UserRole();
                    userRole.setUserId(dto.getUserId());
                    userRole.setRoleId(roleId);
                    userRole.setTenantId(dto.getTenantId());
                    userRole.setCreateTime(now);
                    userRole.setCreateBy(1L); // 这里应该从上下文获取当前用户
                    userRoles.add(userRole);
                }

                int result = userRoleMapper.batchInsert(userRoles);
                if (result <= 0) {
                    throw new BusinessException(ErrorCode.OPERATION_ERROR);
                }
            }

            log.info("更新用户角色成功: userId={}, roleIds={}", dto.getUserId(), dto.getRoleIds());
            return true;
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("更新用户角色失败: userId={}, roleIds={}, error={}", dto.getUserId(), dto.getRoleIds(), e.getMessage(), e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "更新用户角色失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteUserRolesByUserId(Long userId, Long tenantId) throws BusinessException {
        try {
            // 参数校验
            if (userId == null || tenantId == null) {
                throw new BusinessException(ErrorCode.PARAM_ERROR);
            }

            int result = userRoleMapper.deleteByUserId(userId, tenantId);
            
            log.info("删除用户角色关联成功: userId={}, count={}", userId, result);
            return true;
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("删除用户角色关联失败: userId={}, error={}", userId, e.getMessage(), e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "删除用户角色关联失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteUserRolesByRoleId(Long roleId, Long tenantId) throws BusinessException {
        try {
            // 参数校验
            if (roleId == null || tenantId == null) {
                throw new BusinessException(ErrorCode.PARAM_ERROR);
            }

            int result = userRoleMapper.deleteByRoleId(roleId, tenantId);
            
            log.info("删除角色用户关联成功: roleId={}, count={}", roleId, result);
            return true;
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("删除角色用户关联失败: roleId={}, error={}", roleId, e.getMessage(), e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "删除角色用户关联失败: " + e.getMessage());
        }
    }

    @Override
    public UserRoleVO getUserRoleByUserId(Long userId, Long tenantId) throws BusinessException {
        try {
            // 参数校验
            if (userId == null || tenantId == null) {
                throw new BusinessException(ErrorCode.PARAM_ERROR);
            }

            // 查询用户角色关联信息
            List<UserRole> userRoles = userRoleMapper.selectUserRoleByUserId(userId, tenantId);
            if (CollectionUtils.isEmpty(userRoles)) {
                return null;
            }

            // 创建UserRoleVO对象
            UserRoleVO userRoleVO = new UserRoleVO();
            userRoleVO.setUserId(userId);
            userRoleVO.setTenantId(tenantId);

            // 查询用户的角色信息
            List<com.cencat.user.entity.Role> roleEntities = userRoleMapper.selectRolesByUserId(userId, tenantId);
            List<UserRoleVO.RoleInfo> roles = roleEntities.stream()
                    .map(role -> {
                        UserRoleVO.RoleInfo roleInfo = new UserRoleVO.RoleInfo();
                        roleInfo.setRoleId(role.getId());
                        roleInfo.setRoleName(role.getRoleName());
                        roleInfo.setRoleCode(role.getRoleCode());
                        roleInfo.setDescription(role.getDescription());
                        return roleInfo;
                    })
                    .collect(Collectors.toList());
            userRoleVO.setRoles(roles);

            return userRoleVO;
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("查询用户角色详情失败: userId={}, error={}", userId, e.getMessage(), e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "查询用户角色详情失败: " + e.getMessage());
        }
    }

    @Override
    @Cacheable(value = "userRolePage", 
               key = "'tenant:' + #queryDTO.tenantId + ':page:' + #queryDTO.pageNum + ':size:' + #queryDTO.pageSize + ':userId:' + (#queryDTO.userId != null ? #queryDTO.userId : 'null') + ':roleId:' + (#queryDTO.roleId != null ? #queryDTO.roleId : 'null')",
               condition = "#queryDTO != null and #queryDTO.tenantId != null")
    public PageResponse<UserRoleVO> getUserRolePage(UserRoleQueryDTO queryDTO) throws BusinessException {
        try {
            // 参数校验
            if (queryDTO == null || queryDTO.getTenantId() == null) {
                throw new BusinessException(ErrorCode.PARAM_ERROR);
            }

            // 设置默认分页参数
            if (queryDTO.getPageNum() == null || queryDTO.getPageNum() <= 0) {
                queryDTO.setPageNum(1);
            }
            if (queryDTO.getPageSize() == null || queryDTO.getPageSize() <= 0) {
                queryDTO.setPageSize(10);
            }

            // 构建分页查询参数
            PaginationHelper.PageQuery pageQuery = new PaginationHelper.PageQuery();
            pageQuery.setCurrent(queryDTO.getPageNum().longValue());
            pageQuery.setSize(queryDTO.getPageSize().longValue());
            
            // 构建查询条件
            QueryWrapper<UserRole> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("tenant_id", queryDTO.getTenantId());
            
            if (queryDTO.getUserId() != null) {
                queryWrapper.eq("user_id", queryDTO.getUserId());
            }
            
            if (queryDTO.getRoleId() != null) {
                queryWrapper.eq("role_id", queryDTO.getRoleId());
            }
            
            queryWrapper.eq("is_deleted", 0);
            queryWrapper.orderByDesc("create_time");
            
            // 执行分页查询并转换为VO
            return PaginationHelper.executePage(userRoleMapper, pageQuery, queryWrapper, this::convertToVO);
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("分页查询用户角色关联失败: {}", e.getMessage(), e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "分页查询用户角色关联失败: " + e.getMessage());
        }
    }

    @Override
    public List<UserRoleVO> getUserRoleList(UserRoleQueryDTO queryDTO) throws BusinessException {
        try {
            // 参数校验
            if (queryDTO == null || queryDTO.getTenantId() == null) {
                throw new BusinessException(ErrorCode.PARAM_ERROR);
            }

            List<UserRole> userRoles = userRoleMapper.selectUserRoleList(queryDTO);
            return userRoles.stream()
                    .map(this::convertToVO)
                    .collect(Collectors.toList());
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("查询用户角色关联列表失败: {}", e.getMessage(), e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "查询用户角色关联列表失败: " + e.getMessage());
        }
    }

    @Override
    public Boolean checkUserHasRole(Long userId, Long roleId, Long tenantId) throws BusinessException {
        try {
            // 参数校验
            if (userId == null || roleId == null || tenantId == null) {
                throw new BusinessException(ErrorCode.PARAM_ERROR);
            }

            return userRoleMapper.checkUserHasRole(userId, roleId, tenantId);
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("检查用户角色失败: userId={}, roleId={}, error={}", userId, roleId, e.getMessage(), e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "检查用户角色失败: " + e.getMessage());
        }
    }

    @Override
    public Boolean checkUserHasRoleCode(Long userId, String roleCode, Long tenantId) throws BusinessException {
        try {
            // 参数校验
            if (userId == null || roleCode == null || roleCode.trim().isEmpty() || tenantId == null) {
                throw new BusinessException(ErrorCode.PARAM_ERROR);
            }

            return userRoleMapper.checkUserHasRoleCode(userId, roleCode, tenantId);
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("检查用户角色编码失败: userId={}, roleCode={}, error={}", userId, roleCode, e.getMessage(), e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "检查用户角色编码失败: " + e.getMessage());
        }
    }

    @Override
    public List<Long> getUserIdsByRoleIds(List<Long> roleIds, Long tenantId) throws BusinessException {
        try {
            // 参数校验
            if (CollectionUtils.isEmpty(roleIds) || tenantId == null) {
                throw new BusinessException(ErrorCode.PARAM_ERROR);
            }

            return userRoleMapper.selectUserIdsByRoleIds(roleIds, tenantId);
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("根据角色ID查询用户ID失败: roleIds={}, error={}", roleIds, e.getMessage(), e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "根据角色ID查询用户ID失败: " + e.getMessage());
        }
    }

    @Override
    public List<Long> getRoleIdsByUserIds(List<Long> userIds, Long tenantId) throws BusinessException {
        try {
            // 参数校验
            if (CollectionUtils.isEmpty(userIds) || tenantId == null) {
                throw new BusinessException(ErrorCode.PARAM_ERROR);
            }

            return userRoleMapper.selectRoleIdsByUserIds(userIds, tenantId);
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("根据用户ID查询角色ID失败: userIds={}, error={}", userIds, e.getMessage(), e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "根据用户ID查询角色ID失败: " + e.getMessage());
        }
    }

    @Override
    public Long getUserRoleCount(Long tenantId) throws BusinessException {
        try {
            // 参数校验
            if (tenantId == null) {
                throw new BusinessException(ErrorCode.PARAM_ERROR);
            }

            return userRoleMapper.countUserRoles(tenantId);
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("统计用户角色关联数量失败: tenantId={}, error={}", tenantId, e.getMessage(), e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "统计用户角色关联数量失败: " + e.getMessage());
        }
    }

    @Override
    public Long getRoleCountByUserId(Long userId, Long tenantId) throws BusinessException {
        try {
            // 参数校验
            if (userId == null || tenantId == null) {
                throw new BusinessException(ErrorCode.PARAM_ERROR);
            }

            return userRoleMapper.countRolesByUserId(userId, tenantId);
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("统计用户角色数量失败: userId={}, error={}", userId, e.getMessage(), e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "统计用户角色数量失败: " + e.getMessage());
        }
    }

    @Override
    public Long getUserCountByRoleId(Long roleId, Long tenantId) throws BusinessException {
        try {
            // 参数校验
            if (roleId == null || tenantId == null) {
                throw new BusinessException(ErrorCode.PARAM_ERROR);
            }

            return userRoleMapper.countUsersByRoleId(roleId, tenantId);
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("统计角色用户数量失败: roleId={}, error={}", roleId, e.getMessage(), e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "统计角色用户数量失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean batchAssignRolesToUsers(List<Long> userIds, List<Long> roleIds, Long tenantId) throws BusinessException {
        try {
            // 参数校验
            if (CollectionUtils.isEmpty(userIds) || CollectionUtils.isEmpty(roleIds) || tenantId == null) {
                throw new BusinessException(ErrorCode.PARAM_ERROR);
            }

            List<UserRole> userRoles = new ArrayList<>();
            LocalDateTime now = LocalDateTime.now();
            
            for (Long userId : userIds) {
                for (Long roleId : roleIds) {
                    // 检查是否已存在关联关系
                    UserRole existingUserRole = userRoleMapper.selectByUserIdAndRoleId(userId, roleId, tenantId);
                    if (existingUserRole == null) {
                        UserRole userRole = new UserRole();
                        userRole.setUserId(userId);
                        userRole.setRoleId(roleId);
                        userRole.setTenantId(tenantId);
                        userRole.setCreateTime(now);
                        userRole.setCreateBy(1L);
                        userRoles.add(userRole);
                    }
                }
            }

            if (!CollectionUtils.isEmpty(userRoles)) {
                int result = userRoleMapper.batchInsert(userRoles);
                log.info("批量分配角色给用户成功: userIds={}, roleIds={}, count={}", userIds, roleIds, result);
            }

            return true;
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("批量分配角色给用户失败: userIds={}, roleIds={}, error={}", userIds, roleIds, e.getMessage(), e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "批量分配角色给用户失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean batchRemoveRolesFromUsers(List<Long> userIds, List<Long> roleIds, Long tenantId) throws BusinessException {
        try {
            // 参数校验
            if (CollectionUtils.isEmpty(userIds) || CollectionUtils.isEmpty(roleIds) || tenantId == null) {
                throw new BusinessException(ErrorCode.PARAM_ERROR);
            }

            int totalCount = 0;
            for (Long userId : userIds) {
                int result = userRoleMapper.deleteByUserIdAndRoleIds(userId, roleIds, tenantId);
                totalCount += result;
            }

            log.info("批量移除用户角色成功: userIds={}, roleIds={}, count={}", userIds, roleIds, totalCount);
            return true;
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("批量移除用户角色失败: userIds={}, roleIds={}, error={}", userIds, roleIds, e.getMessage(), e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "批量移除用户角色失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean copyUserRoles(Long sourceUserId, Long targetUserId, Long tenantId) throws BusinessException {
        try {
            // 参数校验
            if (sourceUserId == null || targetUserId == null || tenantId == null) {
                throw new BusinessException(ErrorCode.PARAM_ERROR);
            }

            // 查询源用户的角色
            List<UserRole> sourceUserRoles = userRoleMapper.selectByUserId(sourceUserId, tenantId);
            if (CollectionUtils.isEmpty(sourceUserRoles)) {
                log.info("源用户没有角色，无需复制: sourceUserId={}", sourceUserId);
                return true;
            }

            // 先删除目标用户的所有角色
            userRoleMapper.deleteByUserId(targetUserId, tenantId);

            // 复制角色给目标用户
            List<UserRole> targetUserRoles = new ArrayList<>();
            LocalDateTime now = LocalDateTime.now();
            
            for (UserRole sourceUserRole : sourceUserRoles) {
                UserRole targetUserRole = new UserRole();
                targetUserRole.setUserId(targetUserId);
                targetUserRole.setRoleId(sourceUserRole.getRoleId());
                targetUserRole.setTenantId(tenantId);
                targetUserRole.setCreateTime(now);
                targetUserRole.setCreateBy(1L);
                targetUserRoles.add(targetUserRole);
            }

            int result = userRoleMapper.batchInsert(targetUserRoles);
            
            log.info("复制用户角色成功: sourceUserId={}, targetUserId={}, count={}", sourceUserId, targetUserId, result);
            return true;
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("复制用户角色失败: sourceUserId={}, targetUserId={}, error={}", sourceUserId, targetUserId, e.getMessage(), e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "复制用户角色失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean syncUserRoles(Long userId, Long tenantId) throws BusinessException {
        try {
            // 参数校验
            if (userId == null || tenantId == null) {
                throw new BusinessException(ErrorCode.PARAM_ERROR);
            }

            // TODO: 根据用户的部门、职位等信息自动分配角色
            // 这里需要根据具体的业务规则来实现
            // 例如：
            // 1. 查询用户的部门信息
            // 2. 根据部门配置的默认角色进行分配
            // 3. 根据用户的职位级别分配相应权限的角色
            
            log.info("同步用户角色: userId={}, tenantId={}", userId, tenantId);
            return true;
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("同步用户角色失败: userId={}, error={}", userId, e.getMessage(), e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "同步用户角色失败: " + e.getMessage());
        }
    }

    /**
     * 将UserRole实体转换为UserRoleVO
     * @param userRole UserRole实体
     * @return UserRoleVO
     */
    private UserRoleVO convertToVO(UserRole userRole) {
        UserRoleVO userRoleVO = new UserRoleVO();
        BeanUtils.copyProperties(userRole, userRoleVO);
        return userRoleVO;
    }
}